package io.renren.service.impl;

import io.renren.common.utils.ConfigConstant;
import io.renren.common.utils.DateUtils;
import io.renren.common.utils.DecimalUtils;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.ProjectConstant;
import io.renren.common.utils.Query;
import io.renren.common.validator.Assert;
import io.renren.controller.WebSocketRoom;
import io.renren.dao.GrabPacketDao;
import io.renren.entity.BalanceDetailEntity;
import io.renren.entity.GrabPacketEntity;
import io.renren.entity.MemberConfigEntity;
import io.renren.entity.MemberEntity;
import io.renren.entity.RoomEntity;
import io.renren.entity.SendPacketEntity;
import io.renren.service.BalanceDetailService;
import io.renren.service.GrabPacketService;
import io.renren.service.MemberConfigService;
import io.renren.service.MemberService;
import io.renren.service.RoomService;
import io.renren.service.SendPacketService;
import io.renren.service.SysConfigService;
import io.renren.service.TeamService;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;

@Service("grabPacketService")
public class GrabPacketServiceImpl extends ServiceImpl<GrabPacketDao, GrabPacketEntity> implements GrabPacketService {

	@Autowired
	MemberService memberService;

	@Autowired
	MemberConfigService memberConfigService;

	@Autowired
	RoomService roomService;

	@Autowired
	SendPacketService sendPacketService;

	@Autowired
	BalanceDetailService balanceDetailService;

	@Autowired
	SysConfigService sysConfigService;

	@Autowired
	TeamService teamService;

	private static final Random RANDOM = new Random();

	@Override
	public PageUtils queryPage(Map<String, Object> params) {
		Page<GrabPacketEntity> page = this.selectPage(new Query<GrabPacketEntity>(params).getPage(), new EntityWrapper<GrabPacketEntity>());

		return new PageUtils(page);
	}

	@Override
	public double robotProfitByRoomId(Long roomId, Date startDate) {
		Assert.notNull(roomId, "roomId is null");
		BigDecimal profitSend = (BigDecimal) this.selectObj(new EntityWrapper<GrabPacketEntity>().setSqlSelect("ifnull(sum(cast(landmine_amount as decimal(18,4))),0)-ifnull(sum(cast(grab_amount as decimal(18,4))),0)").eq("is_robot", ProjectConstant.COMMON_NO)
				.ge(startDate != null, "create_time", startDate).where("send_packet_id in (select t1.id from tb_send_packet t1 where t1.is_robot=1 and t1.room_id={0})", roomId));

		BigDecimal profitGrab = (BigDecimal) this.selectObj(new EntityWrapper<GrabPacketEntity>().setSqlSelect("ifnull(sum(cast(grab_amount as decimal(18,4))),0)-ifnull(sum(cast(landmine_amount as decimal(18,4))),0)").eq("is_robot", ProjectConstant.COMMON_YES)
				.ge(startDate != null, "create_time", startDate).where("send_packet_id in (select t1.id from tb_send_packet t1 where t1.is_robot=0 and t1.room_id={0})", roomId));

		return profitSend.add(profitGrab).doubleValue();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public GrabPacketEntity grab(MemberEntity grabMember, Long id) {

		Date now = new Date();
		SendPacketEntity send = sendPacketService.selectById(id);
		Assert.notNull(send, "红包不存在");
		Assert.isTrue(!grabMember.getId().equals(send.getMemberId()), "不能抢自己的红包");
		Assert.isTrue(send.getStatus() == ProjectConstant.PACKET_STATUS_INITIAL, "红包已结束");
		Assert.isTrue(now.getTime() <= DateUtils.addDateMinutes(send.getCreateTime(), sysConfigService.getValueI(ConfigConstant.PACKET_EXPIRE)).getTime(), "红包已结束");
		Assert.isTrue(this.selectCount(new EntityWrapper<GrabPacketEntity>().eq("send_packet_id", id).eq("grab_member_id", grabMember.getId())) == 0, "您已抢过此红包");
		Assert.isTrue(send.getBalanceQty() > 0, "您的手数慢了一点,红包已被抢完");

		// 中雷赔钱金额
		double landmineAmount = DecimalUtils.mul(send.getAmount(), send.getLandReturnRate());

		GrabPacketEntity grab = new GrabPacketEntity();
		MemberEntity sendMember = memberService.selectById(send.getMemberId());
		// 是否为机器人
		if (grabMember.getUserLevel() == ProjectConstant.USER_LEVEL_ROBOT) {
			grab.setIsRobot(ProjectConstant.COMMON_YES);
		} else {
			Assert.isTrue(send.getRoomId().equals(grabMember.getRoomId()), "您不在此房间");
			Assert.isTrue(grabMember.getBalance() >= landmineAmount, "您的金币不足,请先充值");
			grab.setIsRobot(ProjectConstant.COMMON_NO);
		}

		List<BalanceDetailEntity> details = new ArrayList<BalanceDetailEntity>();

		// 计算抢包金额 判断是否中雷
		double grabAmount = send.getBalanceQty() == 1 ? (new BigDecimal(send.getBalanceAmount().toString()).setScale(2, BigDecimal.ROUND_DOWN).doubleValue()) : this.computeGrabAmount(grabMember, sendMember, send, grab);
		if (isLandmine(grabAmount, send.getLandmine())) {
			grab.setIsLandmine(ProjectConstant.COMMON_YES);// 中雷
			grab.setLandmineAmount(landmineAmount);

			// 抢包者余额变化
			grabMember.setBalance(DecimalUtils.sub(DecimalUtils.add(grabMember.getBalance(), grabAmount), landmineAmount));
			// 发包者余额变化
			sendMember.setBalance(DecimalUtils.add(sendMember.getBalance(), landmineAmount));
			// 机器人不更余额
			if (send.getIsRobot() == ProjectConstant.COMMON_NO) {
				Assert.isTrue(memberService.updateById(sendMember), "您的手速过快,请重试");
			}

			// 插入踩雷者资金明细
			if (grab.getIsRobot() == ProjectConstant.COMMON_NO) {
				BalanceDetailEntity grabDetail = new BalanceDetailEntity();
				grabDetail.setMemberId(grabMember.getId());
				grabDetail.setBalanceChange(DecimalUtils.sub(0, landmineAmount));
				grabDetail.setType(ProjectConstant.ORDER_TYPE_LANDMINE);
				grabDetail.setDescription("中雷支出");
				grabDetail.setCreateTime(now);
				grabDetail.setPacketId(id);
				details.add(grabDetail);
			}

			// 插入发包者资金明细
			if (send.getIsRobot() == ProjectConstant.COMMON_NO) {
				BalanceDetailEntity sendDetail = new BalanceDetailEntity();
				sendDetail.setMemberId(send.getMemberId());
				sendDetail.setBalanceChange(landmineAmount);
				sendDetail.setType(ProjectConstant.ORDER_TYPE_LANDMINE);
				sendDetail.setDescription("中雷收入");
				sendDetail.setCreateTime(now);
				sendDetail.setPacketId(id);
				details.add(sendDetail);
			}

		} else {
			grab.setIsLandmine(ProjectConstant.COMMON_NO);
			// 抢包者余额变化
			grabMember.setBalance(DecimalUtils.add(grabMember.getBalance(), grabAmount));
		}
		// 控制可提现金额
		if (grab.getIsRobot() == ProjectConstant.COMMON_NO && grabMember.getWithdrawAmountLimit() > 0) {
			if (grab.getIsLandmine() == ProjectConstant.COMMON_YES) {
				grabMember.setWithdrawAmountLimit(DecimalUtils.sub(DecimalUtils.sub(grabMember.getWithdrawAmountLimit(), grabAmount), landmineAmount));
			} else {
				grabMember.setWithdrawAmountLimit(DecimalUtils.sub(grabMember.getWithdrawAmountLimit(), grabAmount));
			}
			if (grabMember.getWithdrawAmountLimit() < 0) {
				grabMember.setWithdrawAmountLimit(0D);
			}
		}
		// 机器人不更余额
		if (grab.getIsRobot() == ProjectConstant.COMMON_NO) {
			Assert.isTrue(memberService.updateById(grabMember), "您的手速过快,请重试");
		}

		// 插入抢包记录
		grab.setSendPacketId(id);
		grab.setGrabMemberId(grabMember.getId());
		grab.setRoomId(send.getRoomId());
		grab.setCreateTime(now);
		grab.setGrabAmount(grabAmount);
		this.insert(grab);

		// 插入抢包者资金明细
		if (grab.getIsRobot() == ProjectConstant.COMMON_NO) {
			BalanceDetailEntity grabDetail = new BalanceDetailEntity();
			grabDetail.setMemberId(grabMember.getId());
			grabDetail.setBalanceChange(grabAmount);
			grabDetail.setType(ProjectConstant.ORDER_TYPE_GRAB_PACKET);
			grabDetail.setDescription("抢红包");
			grabDetail.setCreateTime(now);
			grabDetail.setPacketId(id);
			details.add(grabDetail);
		}

		// 修改红包剩余数量与剩余金币
		send.setUpdateTime(now);
		send.setGrabAmount(DecimalUtils.add(send.getGrabAmount(), grabAmount));
		send.setBalanceAmount(DecimalUtils.sub(send.getBalanceAmount(), grabAmount));
		send.setGrabQty(send.getGrabQty() + 1);
		send.setBalanceQty(send.getPacketQty() - send.getGrabQty());
		if (send.getBalanceQty() == 0) {
			// 避免因发包手续费设置不当导致小数位超过两位从而最后一个红包的小数位可以精确算到
			if (send.getBalanceAmount() != 0) {
				send.setFee(DecimalUtils.add(send.getFee(), send.getBalanceAmount()));
				send.setBalanceAmount(0D);
			}
			send.setStatus(ProjectConstant.PACKET_STATUS_FINISH);
		}
		Assert.isTrue(sendPacketService.updateById(send), "您的手速过快,请重试");

		if (CollectionUtils.isNotEmpty(details)) {
			balanceDetailService.insertBatch(details);
		}

		WebSocketRoom.broadcastRP(send, "grab");// 通知房间会员

		return grab;
	}

	/**
	 * 计算抢包金额
	 * 
	 * @param grabMember
	 * @param sendMember
	 * @param send
	 */
	private double computeGrabAmount(MemberEntity grabMember, MemberEntity sendMember, SendPacketEntity send, GrabPacketEntity grab) {
		// 随机分配抢包金额
		double amount = getRandomMoney(send.getBalanceQty(), send.getBalanceAmount());

		// 完全随机可能
		if (RANDOM.nextInt(100) < sysConfigService.getValueI(ConfigConstant.RANDOM_RATE)) {
			return amount;
		}

		Date startOfDay = DateUtils.getStartOfDay(new Date());
		MemberConfigEntity sendMemberConfig = memberConfigService.selectById(sendMember.getId());
		MemberConfigEntity grabMemberConfig = memberConfigService.selectById(grabMember.getId());
		RoomEntity room = roomService.selectOne(new EntityWrapper<RoomEntity>().setSqlSelect("robot_landmine_rate,member_landmine_rate,point_time,profit_limit,loss_limit").eq("id", send.getRoomId()));
		double roomProfit = this.robotProfitByRoomId(send.getRoomId(), room.getPointTime() == null ? startOfDay : room.getPointTime());// 房间盈利
		int memberLandmineRate = room.getMemberLandmineRate();// 会员踩雷概率
		int robotLandmineRate = room.getRobotLandmineRate();// 机器人踩雷概率
		if (grabMemberConfig == null && sendMemberConfig == null) {

			if (grab.getIsRobot() == ProjectConstant.COMMON_YES && send.getIsRobot() == ProjectConstant.COMMON_YES) {
				return modifyLandmineAmount(amount, send.getLandmine(), RANDOM.nextInt(100) < memberLandmineRate ? true : false);
			} else if (grab.getIsRobot() == ProjectConstant.COMMON_YES) {
				// 房间控制
				if (room.getProfitLimit() != null && roomProfit > room.getProfitLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), true);
				} else if (room.getLossLimit() != null && roomProfit < room.getLossLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), false);
				} else {
					return modifyLandmineAmount(amount, send.getLandmine(), RANDOM.nextInt(100) < robotLandmineRate ? true : false);
				}
			} else if (send.getIsRobot() == ProjectConstant.COMMON_YES) {
				// 房间控制
				if (room.getProfitLimit() != null && roomProfit > room.getProfitLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), false);
				} else if (room.getLossLimit() != null && roomProfit < room.getLossLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), true);
				} else {
					return modifyLandmineAmount(amount, send.getLandmine(), RANDOM.nextInt(100) < memberLandmineRate ? true : false);
				}
			}

			return amount;
		}

		// 此人最近N条记录中雷概率超过配置的最大中雷概率后抢包金额就完全随机
		double lr = getLandmineRate(grabMember.getId());
		if (grabMemberConfig != null && grabMemberConfig.getLandmineRateMax() != null) {
			if (lr > grabMemberConfig.getLandmineRateMax()) {
				return amount;
			}
		} else if (lr > sysConfigService.getValueD(ConfigConstant.LANDMINE_RATE_MAX)) {
			return amount;
		}

		// 发包者与抢包者盈亏
		double sendProfit = DecimalUtils.add(balanceDetailService.myProfit(sendMember.getId(), sendMemberConfig == null ? startOfDay : sendMemberConfig.getPointTime()), amount);
		double grabProfit = DecimalUtils.add(balanceDetailService.myProfit(grabMember.getId(), grabMemberConfig == null ? startOfDay : grabMemberConfig.getPointTime()), amount);

		if (sendProfit > grabProfit) {

			// 优先判断盈利少的会员配置信息
			if (grabMemberConfig != null) {
				// 抢包者超过最大亏损(不中雷)
				if (grabMemberConfig.getLossLimit() != null && grabProfit < grabMemberConfig.getLossLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), false);
					// 抢包者超过最大盈利(中雷)
				} else if (grabMemberConfig.getProfitLimit() != null && grabProfit > grabMemberConfig.getProfitLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), true);
				}
			}

			if (sendMemberConfig != null) {
				// 发包者超过最大亏损(中雷)
				if (sendMemberConfig.getLossLimit() != null && sendProfit < sendMemberConfig.getLossLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), true);
					// 发包者超过最大盈利(不中雷)
				} else if (sendMemberConfig.getProfitLimit() != null && sendProfit > sendMemberConfig.getProfitLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), false);
				}
			}

		} else {
			// 优先判断盈利少的会员配置信息
			if (sendMemberConfig != null) {
				// 发包者超过最大亏损(中雷)
				if (sendMemberConfig.getLossLimit() != null && sendProfit < sendMemberConfig.getLossLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), true);
					// 发包者超过最大盈利(不中雷)
				} else if (sendMemberConfig.getProfitLimit() != null && sendProfit > sendMemberConfig.getProfitLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), false);
				}
			}
			if (grabMemberConfig != null) {
				// 抢包者超过最大亏损(不中雷)
				if (grabMemberConfig.getLossLimit() != null && grabProfit < grabMemberConfig.getLossLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), false);
					// 抢包者超过最大盈利(中雷)
				} else if (grabMemberConfig.getProfitLimit() != null && grabProfit > grabMemberConfig.getProfitLimit()) {
					return modifyLandmineAmount(amount, send.getLandmine(), true);
				}
			}
		}

		if (grab.getIsRobot() == ProjectConstant.COMMON_YES && send.getIsRobot() == ProjectConstant.COMMON_YES) {
			return modifyLandmineAmount(amount, send.getLandmine(), RANDOM.nextInt(100) < memberLandmineRate ? true : false);
		} else if (grab.getIsRobot() == ProjectConstant.COMMON_YES) {
			// 房间控制
			if (room.getProfitLimit() != null && roomProfit > room.getProfitLimit()) {
				return modifyLandmineAmount(amount, send.getLandmine(), true);
			} else if (room.getLossLimit() != null && roomProfit < room.getLossLimit()) {
				return modifyLandmineAmount(amount, send.getLandmine(), false);
			} else {
				return modifyLandmineAmount(amount, send.getLandmine(), RANDOM.nextInt(100) < robotLandmineRate ? true : false);
			}
		} else if (send.getIsRobot() == ProjectConstant.COMMON_YES) {
			// 房间控制
			if (room.getProfitLimit() != null && roomProfit > room.getProfitLimit()) {
				return modifyLandmineAmount(amount, send.getLandmine(), false);
			} else if (room.getLossLimit() != null && roomProfit < room.getLossLimit()) {
				return modifyLandmineAmount(amount, send.getLandmine(), true);
			} else {
				return modifyLandmineAmount(amount, send.getLandmine(), RANDOM.nextInt(100) < memberLandmineRate ? true : false);
			}
		}

		return amount;
	}

	/**
	 * 随机红包金额
	 * 
	 * @param qty
	 *            剩余的红包数量
	 * @param balance
	 *            剩余的红包金额
	 * @return
	 */
	private double getRandomMoney(int qty, double balance) {
		if (qty == 1) {
			return balance;
		}
		double min = 0.01;
		double max = balance / qty * 2;
		double money = RANDOM.nextDouble() * max;
		money = money <= min ? 0.01 : money;
		money = Math.floor(money * 100) / 100;
		return money;
	}

	/**
	 * 修改随机红包金额
	 * 
	 * @param amount
	 *            红包金额
	 * @param landmine
	 *            雷点
	 * @param flag
	 *            是否中雷
	 * @return
	 */
	private double modifyLandmineAmount(double amount, int landmine, boolean flag) {

		if (flag && isLandmine(amount, landmine)) {
			return amount;
		} else if (!flag && !isLandmine(amount, landmine)) {
			return amount;
		}

		if (amount == 0.01) {
			return 0.01;// 为了避免抢包者会有0元的情况,没办法它只能中雷
		} else {
			return modifyLandmineAmount(DecimalUtils.sub(amount, 0.01), landmine, flag);
		}
	}

	/**
	 * 是否中雷
	 * 
	 * @param amount
	 * @param landmine
	 * @return
	 */
	private boolean isLandmine(double amount, int landmine) {
		DecimalFormat df = new DecimalFormat("0.00"); 
		String amountStr = df.format(amount);
		// 没有两位小数位的情况
		if (amountStr.indexOf('.') == -1 || amountStr.split("\\.")[1].length() != 2) {
			return 0 == landmine;
		}
		if ((amountStr.charAt(amountStr.length() - 1) - '0') == landmine) {
			return true;
		}
		return false;
	}

	/**
	 * 获取中雷概率
	 * 
	 * @param memberId
	 * @return
	 */
	private double getLandmineRate(Long memberId) {
		List<GrabPacketEntity> list = this.selectList(new EntityWrapper<GrabPacketEntity>().setSqlSelect("is_landmine").eq("grab_member_id", memberId).orderBy("create_time", false).last("limit " + sysConfigService.getValueI(ConfigConstant.LANDMINE_RATE_BASE)));
		int landmine = 0;
		if (CollectionUtils.isNotEmpty(list)) {
			for (GrabPacketEntity grabPacketEntity : list) {
				if (grabPacketEntity.getIsLandmine() == ProjectConstant.COMMON_YES) {
					landmine++;
				}
			}
			return landmine / list.size();
		}
		return 0;
	}
}
